#include "AftermathShaderDatabase.hpp"

namespace PathFinder
{

    void AftermathShaderDatabase::AddShader(const HAL::Shader& shader)
    {

    }

    void AftermathShaderDatabase::AddLibrary(const HAL::Library& shader)
    {

    }

    void AftermathShaderDatabase::AddCompiledObject(const Binary& binary, const Binary& pdb, const std::string& debugName)
    {
        D3D12_SHADER_BYTECODE bytecode{ binary.Bytecode, binary.Length };
        GFSDK_Aftermath_ShaderHash shaderHash;
        GFSDK_Aftermath_ShaderInstructionsHash shaderInstructionsHash;

        AFTERMATH_CHECK_ERROR(GFSDK_Aftermath_GetShaderHash(
            GFSDK_Aftermath_Version_API,
            &bytecode,
            &shaderHash,
            &shaderInstructionsHash));

        mShaderBinaries[shaderHash] = binary;
        mShaderInstructionsToShaderHash[shaderInstructionsHash] = shaderHash;

        // Populate shader debug name.
        // The shaders used in this sample are compiled with compiler-generated debug data
        // file names. That means the debug data file's name matches the corresponding shader's DebugName.
        // If shaders are built with user-defined debug data file names, the shader database
        // must maintain a mapping between the shader DebugName (queried from the shader
        // binary with GFSDK_Aftermath_GetShaderDebugName()) and the name of the file
        // containing the corresponding debug data.
         //Please see the documentation of GFSDK_Aftermath_GpuCrashDump_GenerateJSON() for
        // additional information.
        GFSDK_Aftermath_ShaderDebugName aftermathDebugName;
        strncpy_s(aftermathDebugName.name, debugName.c_str(), debugName.length());

        // Store the data for shader instruction address mapping when decoding GPU crash dumps.
        // cf. FindSourceShaderDebugData()
        //mSourceShaderDebugData[aftermathDebugName] = { pdb.Bytecode, pdb.Length };
    }

    // Find a shader bytecode binary by shader hash.
    const AftermathShaderDatabase::Binary* AftermathShaderDatabase::FindShaderBinary(const GFSDK_Aftermath_ShaderHash& shaderHash) const
    {
        // Find shader binary data for the shader hash
        auto i_shader = mShaderBinaries.find(shaderHash);
        if (i_shader == mShaderBinaries.end())
        {
            // Nothing found.
            return nullptr;
        }

        return &i_shader->second;
    }

    // Find a shader bytecode binary by shader instruction hash.
    const AftermathShaderDatabase::Binary* AftermathShaderDatabase::FindShaderBinary(const GFSDK_Aftermath_ShaderInstructionsHash& shaderInstructionsHash) const
    {
        // First, find shader hash corresponding to shader instruction hash.
        auto i_shaderHash = mShaderInstructionsToShaderHash.find(shaderInstructionsHash);
        if (i_shaderHash == mShaderInstructionsToShaderHash.end())
        {
            // Nothing found.
            return nullptr;
        }

        // Find shader binary data
        const GFSDK_Aftermath_ShaderHash& shaderHash = i_shaderHash->second;
        return FindShaderBinary(shaderHash);
    }

    // Find a source shader debug info by shader debug name generated by the DXC compiler.
    const AftermathShaderDatabase::Binary* AftermathShaderDatabase::FindSourceShaderDebugData(const GFSDK_Aftermath_ShaderDebugName& shaderDebugName) const
    {
        // Find shader debug data for the shader debug name.
        auto i_data = mSourceShaderDebugData.find(shaderDebugName);
        if (i_data == mSourceShaderDebugData.end())
        {
            // Nothing found.
            return nullptr;
        }

        return &i_data->second;
    }

}
